package model.datasource;
import org.apache.commons.lang3.StringUtils;
import org.omg.CORBA.portable.ApplicationException;

import common.Constants;


import java.io.BufferedReader;
import java.io.File;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

import java.nio.charset.Charset;
import java.nio.file.CopyOption;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.StringTokenizer;

import model.Lesson;
import model.Student;
import model.impl.LessonImpl;
import model.impl.StudentImpl;

public class FilePlainTextDataSource implements DataSource
{
	private String studs_fileName;
	private String lessons_filename;
	private int lastInsertedStudentId = -1; // This is used as StudentID
	private int lastInsertedLessonId = -1;
	private Path studs_path;
	private Path lessons_path;
	public FilePlainTextDataSource(String fileName)
	{
		this.studs_fileName = fileName + "_s.txt";
		this.lessons_filename = fileName + "_l.txt";
		studs_path = Paths.get(System.getProperty("user.home"), Constants.PROJECT, studs_fileName);
		if(!Files.exists(studs_path))
		{
			try
			{
				Files.createDirectories(studs_path.getParent());
				Files.createFile(studs_path);
			}
			catch (IOException e)
			{
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		lessons_path = Paths.get(System.getProperty("user.home"), Constants.PROJECT, lessons_filename);
	
		if(!Files.exists(lessons_path))
		{
			try
			{
				Files.createDirectories(lessons_path.getParent());
				Files.createFile(lessons_path);
			}
			catch (IOException e)
			{
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		lastInsertedStudentId = -1;
		lastInsertedLessonId = -1;
	}
	@Override
	public Lesson addNewLesson(Student s, String title, String content, Date date, int income)
	{
		// TODO Auto-generated method stub
		try
		{
			if(lastInsertedLessonId < 0)
			{
				String line = null;
				
				BufferedReader br = new BufferedReader(new FileReader(lessons_path.toFile()));
				while((line = br.readLine()) != null)
				{
					String [] data = line.split(";");
					lastInsertedLessonId = Integer.parseInt(data[0]);
				}
				br.close();
			}
			
			// set next student's id
			lastInsertedLessonId = lastInsertedLessonId < 0 ? 1 : lastInsertedLessonId + 1;
			String s_date = new SimpleDateFormat(Constants.dateFormat).format(date);
			String [] data = { "" + lastInsertedLessonId, "" + s.getId(), s.getName(), title, content, s_date, "" + income };
			String line = StringUtils.join(data, ";");
			

			FileWriter fw = new FileWriter(lessons_path.toFile(), true);
			fw.write(line);
			fw.write('\n');
			fw.flush();
			fw.close();
			
			return new LessonImpl(lastInsertedLessonId, title, content, s, income, date);
			
		}
		catch(IOException e)
		{
			e.printStackTrace();
		}
		return null;
	}
	@Override
	public Student addNewStudent(String name, String lastName, String nickName, String email, String school, String phoneNumber, int year)
	{
		// TODO Auto-generated method stub
		try
		{
			// find last inserted student and get its id
			if(lastInsertedStudentId < 0)
			{
				String line = null;
			
				BufferedReader br = new BufferedReader(new FileReader(studs_path.toFile()));
				while((line = br.readLine()) != null)
				{
					String [] data = line.split(";");
					lastInsertedStudentId = Integer.parseInt(data[0]);
				}
				br.close();
			}
			// set next student's id
			lastInsertedStudentId = lastInsertedStudentId < 0 ? 1 : lastInsertedStudentId + 1;
			String [] data = { "" + lastInsertedStudentId, name, lastName, nickName, email, school, phoneNumber, "" + year };
			String line = StringUtils.join(data, ";");
			

			FileWriter fw = new FileWriter(studs_path.toFile(), true);
			fw.write(line);
			fw.write('\n');
			fw.flush();
			fw.close();
			
			return new StudentImpl(lastInsertedStudentId, name, lastName, nickName, email, school, phoneNumber, year);
		}
		catch(IOException e)
		{
			e.printStackTrace();
		}
		return null;
	}
	@Override
	public Collection<Lesson> requestAllLessons()
	{
		// TODO Auto-generated method stub
		List<Lesson> lessons = null;
		try
		{
			List<String> lines = Files.readAllLines(this.lessons_path,  Charset.defaultCharset());
			lessons = new ArrayList<Lesson>();
			if( lines != null )
			{
				for( String line : lines )
				{
					String [] attr = line.split(";");
					int id = Integer.parseInt(attr[0]);
					int studId = Integer.parseInt(attr[1]);
					Student s = new StudentImpl(studId, attr[2], null, null, null,null, null, 0);				
					Lesson l = new LessonImpl(id, attr[3], attr[4], s, Integer.parseInt(attr[6]), new SimpleDateFormat(Constants.dateFormat).parse(attr[5]));
					lessons.add(l);
				}
			}
		}
		catch(IOException e)
		{
			e.printStackTrace();
		}
		catch(ParseException e)
		{
			e.printStackTrace();
		}
		return lessons;
	}
	@Override
	public Collection<Student> requestAllStudents()
	{
		// TODO Auto-generated method stub
		List<Student> students = null;
		try
		{
			List<String> lines = Files.readAllLines(this.studs_path, Charset.defaultCharset());
			students = new ArrayList<Student>();
			if( lines != null )
			{							
				for( String line : lines )
				{
					String [] attr = line.split(";");
					int id = Integer.parseInt(attr[0]);
					Student s = new StudentImpl(id, attr[1], attr[2], attr[3], attr[4], attr[5], attr[6], Integer.parseInt(attr[7]));
					students.add(s);
				}
			}			
		}
		catch(IOException e)
		{
			e.printStackTrace();			
		}
		return students;
	}
	@Override
	public int deleteStudent(int id)
	{
		// TODO Auto-generated method stub
		return this.deleteEntry(id,  this.studs_path);
	}
	
	@Override
	public int deleteLesson(int id)
	{
		// TODO Auto-generated method stub
		return this.deleteEntry(id, this.lessons_path);
	}
	
	private int updateEntry(Path path, int id, java.util.Collection<String> data)
	{
		Path tempPath = null;
		boolean found = false;
		String updatedLine = "" + id + ";";
		for( String d : data )
		{
			updatedLine += d + ";";
		}
		try
		{
			// crete temp file and copy original file into it			
			tempPath = Files.createTempFile(path.getParent(), "tmp", "");
			Files.copy(path, tempPath, StandardCopyOption.REPLACE_EXISTING);
			// read all students
			List<String> lines = Files.readAllLines(tempPath, Charset.defaultCharset());
			FileWriter fw = new FileWriter(path.toFile());
			if( lines != null )
			{
				for( String line : lines )
				{
					StringTokenizer st = new StringTokenizer(line, ";");
					int entry_id = Integer.parseInt(st.nextToken());
					if( id != entry_id )
					{
						fw.write(line + "\n");			
					}
					else
					{
						fw.write(updatedLine + "\n");
						found = true;
					}
				}
				fw.flush();
				fw.close();
				Files.deleteIfExists(tempPath); // remove temporary file
			}
		}
		catch(IOException e)
		{
			// copy back temp file to original
			if(tempPath != null)
			{
				try
				{
					Files.copy(tempPath, path, StandardCopyOption.REPLACE_EXISTING);
				}
				catch (IOException e1)
				{
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
			}
			e.printStackTrace();
		}
		return found ? Constants.OK : Constants.ENTRY_NOT_FOUND;
	}
	private int deleteEntry(int id, Path path)
	{
		Path tempPath = null;
		boolean found = false;
		try
		{
			// crete temp file and copy original file into it			
			tempPath = Files.createTempFile(path.getParent(), "tmp", "");
			Files.copy(path, tempPath, StandardCopyOption.REPLACE_EXISTING);
			// read all students
			List<String> lines = Files.readAllLines(tempPath, Charset.defaultCharset());
			FileWriter fw = new FileWriter(path.toFile());
			if( lines != null )
			{
				for( String line : lines )
				{
					StringTokenizer st = new StringTokenizer(line, ";");
					int entry_id = Integer.parseInt(st.nextToken());
					if( id != entry_id )
					{
						fw.write(line + "\n");			
					}
					else
					{
						found = true;
					}
				}
				fw.flush();
				fw.close();
				Files.deleteIfExists(tempPath); // remove temporary file
			}
		}
		catch(IOException e)
		{
			// copy back temp file to original
			if(tempPath != null)
			{
				try
				{
					Files.copy(tempPath, path, StandardCopyOption.REPLACE_EXISTING);
				}
				catch (IOException e1)
				{
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
			}
			e.printStackTrace();
		}
		return found ? Constants.OK : Constants.ENTRY_NOT_FOUND;
	}
	
	@Override
	public Lesson updateLesson(int id, Student s, String title, String content,
			Date date, int income)
	{
		// TODO Auto-generated method stub
		Collection<String> data = new ArrayList<String>();
		data.add("" + s.getId());
		data.add(s.getName());
		data.add(title);
		data.add(content);
		data.add(new SimpleDateFormat(Constants.dateFormat).format(date));
		data.add("" + income);
		
		int res = this.updateEntry(this.lessons_path, id, data);
		if( res == Constants.OK )
		{
			return new LessonImpl(id, title, content, s, income, date);
		}
		else
		{
			return null;
		}
	}
	@Override
	public Student updateStudent(int id, String name, String lastName,
			String nickName, String email, String school, String phoneNumber,
			int year)
	{
		// TODO Auto-generated method stub
		
		Collection<String> data = new ArrayList<String>();
		data.add(name);
		data.add(lastName);
		data.add(nickName);
		data.add(email);
		data.add(school);
		data.add(phoneNumber);
		data.add("" + year);
		
		int res = this.updateEntry(this.studs_path, id, data);
		if( res == Constants.OK )
		{
			return new StudentImpl(id, name, lastName, nickName, email, school, phoneNumber, year);
		}
		else
		{
			return null;
		}
	}
}
